﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.DirectoryServices;
using ActiveDs;

namespace Library
{
  #region LocalGroupクラス
  /// <summary>
  /// ローカルのグループを表すクラスです。
  /// </summary>
  public sealed class LocalGroup : DirectoryObject, IGroup
  {
    #region インターナルコンストラクター
    /// <summary>
    /// <see cref="DirectoryEntry"/> を指定して <see cref="LocalGroup"/> クラスの新しいインスタンスを初期化します。
    /// </summary>
    /// <param name="entry"><see cref="DirectoryEntry"/>。</param>
    internal LocalGroup(DirectoryEntry entry)
      : base(entry)
    {
    }
    #endregion

    #region パブリックプロパティ
    /// <summary>
    /// <see cref="Entry"/> の ADSI Group オブジェクトを取得します。
    /// </summary>
    public IADsGroup Native
    {
      get
      {
        if (base.IsDisposed)
        {
          throw new ObjectDisposedException(this.GetType().Name);
        }
        return (IADsGroup)base.Entry.NativeObject;
      }
    }
    #endregion
  }
  #endregion

  #region DomainGroupクラス
  /// <summary>
  /// ドメインのグループを表すクラスです。
  /// </summary>
  [DataObject()]
  public sealed class DomainGroup : DomainObject, IGroup
  {
    #region プライベートフィールド
    private readonly int _token;
    private readonly bool _security;
    private readonly string _scope, _type;
    private readonly DomainGroupScopeType _scopeType;
    #endregion

    #region インターナルコンストラクター
    /// <summary>
    /// <see cref="DirectoryEntry"/> を指定して <see cref="DomainGroup"/> クラスの新しいインスタンスを初期化します。
    /// </summary>
    /// <param name="entry"><see cref="DirectoryEntry"/>。</param>
    internal DomainGroup(DirectoryEntry entry)
      : base(entry)
    {
      entry.Invoke("GetInfoEx", new object[] { "primaryGroupToken" }, 0);
      _token = Convert.ToInt32(entry.Properties["primaryGroupToken"].Value);

      var gtype = Convert.ToInt32(entry.Properties["groupType"].Value);
      if (gtype < 0)
      {
        _security = true;
        _type = "セキュリティ";
      }
      else
      {
        gtype += Int32.MinValue;
        _type = "配布";
      }
      _scopeType = (DomainGroupScopeType)Enum.ToObject(typeof(DomainGroupScopeType), gtype);
      _scope = GetGroupScope();   //グループのスコープを取得
    }
    #endregion

    #region パブリックプロパティ
    /// <summary>
    /// <see cref="Entry"/> の ADSI Group オブジェクトを取得します。
    /// </summary>
    public IADsGroup Native
    {
      get
      {
        if (base.IsDisposed)
        {
          throw new ObjectDisposedException(this.GetType().Name);
        }
        return (IADsGroup)base.Entry.NativeObject;
      }
    }

    /// <summary>
    /// グループのスコープを取得します。
    /// </summary>
    public string Scope
    {
      get
      {
        return _scope;
      }
    }

    /// <summary>
    /// グループのスコープタイプを取得します。
    /// </summary>
    public DomainGroupScopeType ScopeType
    {
      get
      {
        return _scopeType;
      }
    }

    /// <summary>
    /// セキュリティ グループかどうかを取得します。
    /// </summary>
    public bool SecurityEnabled
    {
      get
      {
        return _security;
      }
    }

    /// <summary>
    /// プライマリ グループ トークンを取得します。
    /// </summary>
    public int Token
    {
      get
      {
        return _token;
      }
    }

    /// <summary>
    /// グループの種類を取得します。
    /// </summary>
    public string Type
    {
      get
      {
        return _type;
      }
    }
    #endregion

    #region パブリックメソッド
    /// <summary>
    /// 指定した名前のグループを検索します。このメソッドはデータバインド用です。
    /// </summary>
    /// <param name="name">名前。</param>
    /// <returns>グループ。</returns>
    [DataObjectMethod(DataObjectMethodType.Select)]
    public static DomainGroup FindByName(string name)
    {
      return (DomainGroup)DirectoryAccess.FindDirectoryObject(name, CategoryType.Group);
    }

    /// <summary>
    /// グループの一覧を取得します。このメソッドはデータバインド用です。
    /// </summary>
    /// <returns>グループの一覧。</returns>
    [DataObjectMethod(DataObjectMethodType.Select)]
    public static IList<DomainGroup> GetGroups()
    {
      return DirectoryAccess.GetGroups<DomainGroup>();  //グループを取得
    }
    #endregion

    #region プライベートメソッド
    /// <summary>
    /// グループのスコープを取得します。
    /// </summary>
    /// <returns>グループのスコープ。</returns>
    private string GetGroupScope()
    {
      switch (this.ScopeType)
      {
        case DomainGroupScopeType.BuiltInLocal:
          return "ビルトイン ローカル";
        case DomainGroupScopeType.DomainLocal:
          return "ドメイン ローカル";
        case DomainGroupScopeType.Global:
          return "グローバル";
        default:
          return "ユニバーサル";
      }
    }
  #endregion
 }
  #endregion
}
